#ifndef DROID_H
#define DROID_H

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/atomics.h>
#include <sys/syscall.h>

#define LOG_TAG "droid-logcat"
#define null (0)
#define int64 long long

#define countof(a) (sizeof(a) / sizeof((a)[0]))

bool strequ(const char*, const char*);

int64 nanotime(); /* wall time */
int64 cputime(); /* of calling thread */

void* mem_allocz(size_t size); /* malloc() and memset(0) */
void* mem_alloc(size_t size);
void  mem_free(void* p);
char* mem_strdup(const char* s);
void* mem_dup(const void* a, size_t bytes);
int64 mem_allocated();
int64 mem_allocations();

int get_cpu_count(); /* number of "online" CPUs */
int get_cpu_configured();
unsigned int get_thread_affinity(); /* number of "configured" CPUs */
bool set_thread_affinity(unsigned int mask);
/* nth_set_bit(0xAA = binary(10101010), 4) = binary(10000000) */
unsigned int nth_set_bit(unsigned int mask, int bit);
/* see note: SMP parallel thread execution below */

int ashmem_create_region(const char *name, size_t size); /* create, set_prot & close ~14 microseconds */
int ashmem_set_prot_region(int fd, int prot);

pthread_mutex_t* ashmem_mutex_create(const char *name); /* lock & unlock ~[234..550] ns uncontested: 86 ns */
void ashmem_mutex_destroy(pthread_mutex_t* m);

sem_t* ashmem_sem_create(const char *name); /* post & wait ~[400..3451] ns uncontested: ~96 ns */
void ashmem_sem_destroy(sem_t* s);

void futex_lock(int volatile* g); /* lock & unlock ~[226..1090] ns; uncontested ~102 ns */
void futex_unlock(int volatile* g);

/* warning free p2ll() ll2p() cast from void* to long long and back */

#pragma GCC diagnostic push "-Wpointer-to-int-cast"
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
inline static int64 p2ll(void *p) { return (int64)p; }
#pragma GCC diagnostic pop "-Wpointer-to-int-cast"

#pragma GCC diagnostic push "-Wint-to-pointer-cast"
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
inline static void* ll2p(int64 ll) { return (void*)ll; }
#pragma GCC diagnostic pop "-Wint-to-pointer-cast"

void ashmem_smoke_test();
void sem_smoke_test();
void mutex_smoke_test();
void futex_smoke_test();

#include "trace.h"
#include "mapsl.h"
#include "mapll.h"
#include "queue.h"
#include "timestamp.h"

/*  // SMP parallel thread execution
    // assuming: tn is thread number and this is the init code of the thread's start_routine:
    if (get_cpu_count() > 0) {
        unsigned int mask = get_thread_affinity();
        unsigned int m = nth_set_bit(mask, tn);
        if (m != 0) {
            bool b = set_thread_affinity(m);
            mask = get_thread_affinity();
            assertion(b && mask == m, "%s set_thread_affinity failed with result %d and mask=0x%08X (expected 0x%08X)", p.label, b, mask, m);
        }
    }
    // assigns "tn"-th thread to a Nth online CPU
*/

#endif /* DROID_H */


